/*
	@file: log/source/LogDispatcher.cpp
	@author: Wolfhead
 */
#include "LogDispatcher.h"
#include <boost/foreach.hpp>


namespace logger
{

LogDispatcher::LogDispatcher()
{

}

LogDispatcher::~LogDispatcher()
{
	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	m_name_map.clear();

	LogRunnerPtr runner_ptr;
	BOOST_FOREACH(runner_ptr, m_runner)
	{
		runner_ptr->stop();
	}

	m_runner.clear();
}

int LogDispatcher::add_logger(
	const std::string& name, 
	const LogOption& option)
{
	// not allow an empty runner
	if (!option.logger_ptr)
	{
		return -1;
	}

	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	if (m_name_map.find(name) == m_name_map.end())
	{
		LogRunnerPtr runner_ptr(new LogRunner(option));

		m_runner.push_back(runner_ptr);
		m_name_map[name] = runner_ptr;

		compute_priority();

		if (option.start_on_create)
		{
			runner_ptr->start();
		}
	}
	else
	{
		return -1;
	}
	
	return 0;
}

int LogDispatcher::start_logger(
	const std::string& name
	)
{
	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	std::map<std::string, LogRunnerPtr>::iterator it =
		m_name_map.find(name);

	if (it == m_name_map.end())
	{
		return -1;
	}

	it->second->start();


	return 0;	
}

int LogDispatcher::start_all()
{
	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	LogRunnerPtr runner_ptr;
	BOOST_FOREACH(runner_ptr, m_runner)
	{
		runner_ptr->start();
	}

	return 0;		
}

int LogDispatcher::delete_logger(const std::string& name)
{
	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	if (m_name_map.find(name) == m_name_map.end())
	{
		return -1;
	}
	else
	{
		LogRunnerPtr runner_ptr = m_name_map[name];

		m_name_map.erase(name);

		for (std::vector<LogRunnerPtr>::iterator it = m_runner.begin();
			 it != m_runner.end();
			 ++it)
		{
			 if (*it == runner_ptr)
			 {
			 	it = m_runner.erase(it);
			 	if (it == m_runner.end())
				{
					break; 	
				}
			 }
		}

		runner_ptr->stop();

		compute_priority();
	}

	return 0;
}

int LogDispatcher::set_logger_option(
	const std::string& name,
	const LogOption& option)
{
	boost::unique_lock<boost::shared_mutex> unique_lock(m_mutex);

	std::map<std::string, LogRunnerPtr>::iterator it =
		m_name_map.find(name);

	if (it == m_name_map.end())
	{
		return -1;
	}

	it->second->set_option(option);

	compute_priority();

	return 0;
}

int LogDispatcher::get_logger_option(
	const std::string& name,
	LogOption& option
	)
{
	boost::shared_lock<boost::shared_mutex> shared_lock(m_mutex);

	std::map<std::string, LogRunnerPtr>::iterator it =
		m_name_map.find(name);

	if (it == m_name_map.end())
	{
		return -1;
	}	

	option = it->second->get_option();

	return 0;
}


int LogDispatcher::log(LogDataPtr data_ptr)
{
	boost::shared_lock<boost::shared_mutex> shared_lock(m_mutex);

	// use priority dispatch
	if (!data_ptr->byname)
	{
		LogRunnerPtr runner_ptr;
		BOOST_FOREACH(runner_ptr, m_runner)
		{
			runner_ptr->log(data_ptr);
		}
	}
	else
	{
		std::map<std::string, LogRunnerPtr>::iterator it =
			m_name_map.find(data_ptr->name);
		if (it == m_name_map.end())
		{
			return -1;
		}

		it->second->log(data_ptr);		
	}
	return 0;
}

int LogDispatcher::get_aggregate_priority()
{
	return m_aggregate_priority;
}

int LogDispatcher::compute_priority()
{
	LogPriority priority = kNone;
	for (size_t i = 0; i != m_runner.size(); ++i)
	{
		priority |= m_runner[i]->get_option().priority;
	}

	m_aggregate_priority = priority;
	return 0;
}

}//namespace logger
